package com.chen.common.util.time;


import com.chen.common.exception.Throw;
import com.chen.common.model.OP;
import com.chen.common.util.StringUtil;

import java.sql.Timestamp;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.util.Date;

/**
 * @author chenzy
 * @since 2020-06-30
 * 时间工具类,主要操作LocalDateTime对象,时区采用北京时间,东八区.
 * java8开始的新时间api,旧的日期api可能有线程安全问题
 *
 */
public class TimeUtil {
    //时区，北京时间
    private final static ZoneOffset zone=ZoneOffset.of("+8");
    private TimeUtil(){}
    /*返回北京时间时区*/
    public static String getTimeZoneId (){
//        TimeZone.getTimeZone("GMT+8").getID();
        return "GMT+8";
    }

    public static Date toDate(LocalDateTime time) {
        return Date.from(time.toInstant(zone));
    }
    public static LocalDateTime date2Time(Date date) {
        return long2Time(date.getTime()).orElse(null);
    }

    public static OP<LocalDateTime> long2Time(Long time) {
        if (time==null){
            return OP.empty();
        }
        try {
            return OP.of(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), zone));
        }catch (Exception e){
            return OP.empty();
        }
//        return LocalDateTime.ofEpochSecond(time/1000,0,ZoneOffset.ofHours(8));//这种只能转成秒，毫秒会被丢失
    }
    public static OP<LocalDate> long2LocalDate(Long time) {
        if (time==null){
            return OP.empty();
        }
        try {
            return OP.of(LocalDate.ofInstant(Instant.ofEpochMilli(time), zone));
        }catch (Exception e){
            return OP.empty();
        }
    }
    public static OP<String> long2Str(Long time,String timeFormat) {
        return long2Time(time).map(d->time2Str(d,timeFormat));
    }
    public static OP<String> long2Str(Long time) {
        return long2Str(time,TimeFormat.DEFAULT);
    }
    /*得到当前日期字符串，默认格式*/
    public static String nowStr(){
       return nowStr(TimeFormat.DEFAULT);
    }
    /*得到当前日期字符串，指定格式*/
    public static String nowStr(String pattern){
        return DateTimeFormatter.ofPattern(pattern).format(now());
    }
    /*得到当前日期字符串，格式yyyy_MM_dd_HH_mm_ss_SSS*/
    public static String nowStrSSS(){
        return nowStr(TimeFormat.yyyy_MM_dd_HH_mm_ss_SSS);
    }
    /**
     * 得到当前日期时间戳
     * @return
     */
    public static Long nowLong(){
        return Timestamp.valueOf(now()).getTime();
//        return time2Long(now());
    }
    public static String nowLongStr(){
        return nowLong().toString();
    }

    public static LocalDateTime now(){
        return LocalDateTime.now(zone);
    }
    public static LocalDate nowDate() {
        return LocalDate.now(zone);
    }

    /*判断字符串是否是日期格式*/
    public static boolean isDate(String time, String pattern) {
        return str2Date(time,pattern).map(i->true).orElse(false);
    }
    /*判断字符串是否是时间格式*/
    public static boolean isTime(String time, String pattern) {
        return str2Time(time,pattern).map(i->true).orElse(false);
    }
    public static boolean isIn(String time, String pattern) {
        return str2Date(time,pattern).map(i->true).orElse(false);
    }
    public static Boolean isIn(LocalDateTime beginTime, LocalDateTime endTime) {
        return isIn(beginTime,endTime,now());
    }
    /**
     * 当时间在指定区间内返回true，包括开始时间和结束时间。
     * @param beginTime 开始时间
     * @param endTime 结束时间
     * @param time 需要比较的时间
     */
    public static Boolean isIn(LocalDateTime beginTime, LocalDateTime endTime, LocalDateTime time) {
        return (time.isEqual(beginTime)||time.isAfter(beginTime))&&(time.isEqual(endTime)||time.isBefore(endTime));
    }
    /**
     * 当日期在指定区间内返回true，包括开始日期和结束日期。
     * @param beginTime 开始日期
     * @param endTime 结束日期
     * @param time 需要比较的日期
     */
    public static Boolean isInDate(LocalDate beginTime, LocalDate endTime, LocalDate time) {
        return (time.isEqual(beginTime)||time.isAfter(beginTime))&&(time.isEqual(endTime)||time.isBefore(endTime));
    }
    public static OP<LocalDateTime> str2Time(String time,String pattern){
        if (StringUtil.isBlankOr(time,pattern)){
            return OP.empty();
        }
        try {
            return OP.ofNullable(LocalDateTime.parse(time,DateTimeFormatter.ofPattern(pattern)));
        }catch (Exception e){
            return OP.empty();
        }

    }
    public static OP<LocalDate> str2Date(String time,String pattern){
        if (StringUtil.isBlankOr(time,pattern)){
            return OP.empty();
        }
        try {
            return OP.ofNullable(LocalDate.parse(time,DateTimeFormatter.ofPattern(pattern)));
        }catch (Exception e){
            return OP.empty();
        }
    }
    /*字符串时间转换到指定格式*/
    public static OP<String> str2Str(String time, String fromPattern, String toPattern) {
        return str2Time(time,fromPattern).map(temp->time2Str(temp,toPattern));
    }

    public static long str2Long(String time, String pattern, long defaultValue) {
        return str2Time(time,pattern).map(temp->time2Long(temp)).orElse(defaultValue);
    }
    public static OP<Long> str2Long(String time,String pattern){
        return str2Time(time,pattern).map(temp->time2Long(temp));
    }
//    public static String time2Str(LocalDateTime time,String pattern){
//        return DateTimeFormatter.ofPattern(pattern).format(time);
//    }
    public static String time2Str(TemporalAccessor time, String pattern){
        return DateTimeFormatter.ofPattern(pattern).format(time);
    }
    public static Long time2Long(LocalDate time){
        if (time==null){
            return 0L;
        }

        return Timestamp.valueOf(time.atStartOfDay()).getTime();
//        return time.toInstant(zone).toEpochMilli();
    }
    public static Long time2Long(LocalDateTime time){
        if (time==null){
            return 0L;
        }
        return Timestamp.valueOf(time).getTime();
//        return time.toInstant(zone).toEpochMilli();
    }
    /*得到时间戳，只精确到秒*/
    public static Long time2LongSecond(LocalDateTime time){
        if (time==null){
            return 0L;
        }
        return time.toEpochSecond(zone);
    }
    /*得到当月总天数*/
    public static int countDays() {
        var date=LocalDate.now(zone).plusMonths(1);
        return date.minusDays(date.getDayOfMonth()).getDayOfMonth();
    }

    /*参数2小于等于参数1*/
    public static boolean ltEqualDay(LocalDateTime time1,LocalDateTime time2){
        return gtDaysCount(time1,time2)<0;
    }
    /*参数2大于参数1的天数*/
    public static int gtDaysCount(LocalDateTime time1,LocalDateTime time2){
        return between(time1,time2,TimeUnitEnum.Day).intValue();
    }
    /*参数2是否大于于参数1*/
    public static boolean gt(LocalDateTime time1,LocalDateTime time2){
        return between(time1,time2,TimeUnitEnum.Second)>0;
    }
    /*参数2大于参数1的年数*/
    public static int gtYearsCount(LocalDateTime time1,LocalDateTime time2){
        return between(time1,time2,TimeUnitEnum.Year).intValue();
    }
    public static Long between(LocalDateTime time1,LocalDateTime time2,TimeUnitEnum timeUnit){
        switch (timeUnit){
            case Second:
                return ChronoUnit.SECONDS.between(time1,time2);
//                return Duration.between(time1,time2).toSeconds();
            case Minute:
                return Duration.between(time1,time2).toMinutes();
            case Hour:
                return ChronoUnit.HOURS.between(time1,time2);
//                return Duration.between(time1,time2).toHours();
            case Day:
                return ChronoUnit.DAYS.between(time1,time2);
//                return Duration.between(time1,time2).toDays();
            case Week:
                return ChronoUnit.WEEKS.between(time1,time2);
            case Month:
                return ChronoUnit.MONTHS.between(time1,time2);
            case Year:
                return ChronoUnit.YEARS.between(time1,time2);
            default:
                throw Throw.errorGet("意料外的时间单位"+timeUnit.name());
        }
    }
    /*当前时间加减，*/
    public static String changeTime(TimeUnitEnum timeUnit,String pattern, int num){
        if (num==0){
            return nowStr(pattern);
        }
        return time2Str(changeTime(now(),timeUnit,num),pattern);
    }
    public static String changeTime(TimeUnitEnum timeUnit, int num){
        return changeTime(timeUnit,TimeFormat.DEFAULT,num);
    }
    public static LocalDateTime changeTime(LocalDateTime dateTime,TimeUnitEnum timeUnit, int num){
        switch (timeUnit){
            case Minute:
                return dateTime.plusMinutes(num);
            case Hour:
                return dateTime.plusHours(num);
            case Day:
                return dateTime.plusDays(num);
            case Week:
                return dateTime.plusWeeks(num);
            case Month:
                return dateTime.plusMonths(num);
            case Year:
                return dateTime.plusYears(num);
            default:
                return dateTime;
        }
    }

    /*得到今日剩余秒数*/
    public static Integer getSecondsLeftToday() {
        Long data=Duration.between(now(),LocalDateTime.of(nowDate(), LocalTime.MAX)).toSeconds();
        return data.intValue();
    }


}
